<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Sloaner文字转语音工具</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            padding: 20px;
        }

        .container {
            max-width: 800px;
            margin: 0 auto;
            background: rgba(255, 255, 255, 0.95);
            backdrop-filter: blur(10px);
            border-radius: 20px;
            padding: 30px;
            box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
        }

        .header {
            text-align: center;
            margin-bottom: 30px;
        }

        .header h1 {
            color: #333;
            font-size: 2.5rem;
            margin-bottom: 10px;
            background: linear-gradient(135deg, #667eea, #764ba2);
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            background-clip: text;
        }

        .header p {
            color: #666;
            font-size: 1.1rem;
        }

        .input-section {
            margin-bottom: 30px;
        }

        .text-input {
            width: 100%;
            min-height: 150px;
            padding: 20px;
            border: 2px solid #e1e5e9;
            border-radius: 15px;
            font-size: 16px;
            line-height: 1.6;
            resize: vertical;
            transition: all 0.3s ease;
            font-family: inherit;
        }

        .text-input:focus {
            outline: none;
            border-color: #667eea;
            box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
        }

        .controls {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 20px;
            margin-bottom: 30px;
        }

        .control-group {
            display: flex;
            flex-direction: column;
            gap: 10px;
        }

        .control-group label {
            font-weight: 600;
            color: #333;
            font-size: 0.95rem;
        }

        .select, .range-input {
            padding: 12px;
            border: 2px solid #e1e5e9;
            border-radius: 10px;
            font-size: 16px;
            transition: all 0.3s ease;
        }

        .select:focus, .range-input:focus {
            outline: none;
            border-color: #667eea;
        }

        .range-container {
            display: flex;
            align-items: center;
            gap: 15px;
        }

        .range-input {
            flex: 1;
            height: 8px;
            background: #e1e5e9;
            border: none;
            border-radius: 4px;
            appearance: none;
        }

        .range-input::-webkit-slider-thumb {
            appearance: none;
            width: 20px;
            height: 20px;
            background: linear-gradient(135deg, #667eea, #764ba2);
            border-radius: 50%;
            cursor: pointer;
            transition: transform 0.2s ease;
        }

        .range-input::-webkit-slider-thumb:hover {
            transform: scale(1.2);
        }

        .range-value {
            min-width: 40px;
            text-align: center;
            font-weight: 600;
            color: #667eea;
        }

        .buttons {
            display: flex;
            flex-wrap: wrap;
            gap: 15px;
            justify-content: center;
            margin-bottom: 30px;
        }

        .btn {
            padding: 15px 30px;
            border: none;
            border-radius: 50px;
            font-size: 16px;
            font-weight: 600;
            cursor: pointer;
            transition: all 0.3s ease;
            position: relative;
            overflow: hidden;
            min-width: 120px;
        }

        .btn-primary {
            background: linear-gradient(135deg, #667eea, #764ba2);
            color: white;
        }

        .btn-secondary {
            background: linear-gradient(135deg, #ffecd2, #fcb69f);
            color: #333;
        }

        .btn-danger {
            background: linear-gradient(135deg, #ff9a9e, #fecfef);
            color: #333;
        }

        .btn-download {
            background: linear-gradient(135deg, #a8edea, #fed6e3);
            color: #333;
        }

        .btn:hover {
            transform: translateY(-2px);
            box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
        }

        .btn:active {
            transform: translateY(0);
        }

        .btn:disabled {
            opacity: 0.6;
            cursor: not-allowed;
            transform: none;
        }

        .status {
            text-align: center;
            margin-bottom: 20px;
            padding: 15px;
            border-radius: 10px;
            font-weight: 500;
        }

        .status.speaking {
            background: linear-gradient(135deg, #d4ffea, #c7f9e3);
            color: #059669;
            border: 2px solid #10b981;
        }

        .status.paused {
            background: linear-gradient(135deg, #fef3c7, #fde68a);
            color: #d97706;
            border: 2px solid #f59e0b;
        }

        .status.stopped {
            background: linear-gradient(135deg, #fee2e2, #fecaca);
            color: #dc2626;
            border: 2px solid #ef4444;
        }

        .progress-bar {
            width: 100%;
            height: 6px;
            background: #e1e5e9;
            border-radius: 3px;
            overflow: hidden;
            margin-top: 10px;
        }

        .progress-fill {
            height: 100%;
            background: linear-gradient(90deg, #667eea, #764ba2);
            width: 0%;
            transition: width 0.3s ease;
        }

        .feature-list {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
            gap: 20px;
            margin-top: 30px;
        }

        .feature-item {
            background: rgba(255, 255, 255, 0.7);
            padding: 20px;
            border-radius: 15px;
            text-align: center;
            border: 2px solid transparent;
            transition: all 0.3s ease;
        }

        .feature-item:hover {
            border-color: #667eea;
            transform: translateY(-5px);
        }

        .feature-icon {
            font-size: 2rem;
            margin-bottom: 10px;
        }

        .feature-title {
            font-weight: 600;
            color: #333;
            margin-bottom: 5px;
        }

        .feature-desc {
            color: #666;
            font-size: 0.9rem;
        }

        @media (max-width: 768px) {
            .container {
                padding: 20px;
            }
            
            .header h1 {
                font-size: 2rem;
            }
            
            .controls {
                grid-template-columns: 1fr;
            }
            
            .buttons {
                flex-direction: column;
            }
            
            .btn {
                width: 100%;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>🎙️ Sloaner文字转语音工具</h1>
            <p>输入文本，选择语音参数，即可生成高质量语音</p>
        </div>

        <div class="input-section">
            <textarea 
                class="text-input" 
                id="textInput" 
                placeholder="请输入要转换为语音的文本内容..."
                maxlength="5000"
            >你好！这是一个文字转语音工具演示。您可以输入任何文本，选择不同的语音、语速和音调参数，然后点击播放按钮来听取语音效果。</textarea>
        </div>

        <div class="controls">
            <div class="control-group">
                <label for="voiceSelect">选择语音</label>
                <select id="voiceSelect" class="select">
                    <option value="">正在加载语音...</option>
                </select>
            </div>

            <div class="control-group">
                <label>语速 (0.1 - 2.0)</label>
                <div class="range-container">
                    <input type="range" id="rateRange" class="range-input" min="0.1" max="2" step="0.1" value="1">
                    <span id="rateValue" class="range-value">1.0</span>
                </div>
            </div>

            <div class="control-group">
                <label>音调 (0 - 2.0)</label>
                <div class="range-container">
                    <input type="range" id="pitchRange" class="range-input" min="0" max="2" step="0.1" value="1">
                    <span id="pitchValue" class="range-value">1.0</span>
                </div>
            </div>

            <div class="control-group">
                <label>音量 (0 - 1.0)</label>
                <div class="range-container">
                    <input type="range" id="volumeRange" class="range-input" min="0" max="1" step="0.1" value="1">
                    <span id="volumeValue" class="range-value">1.0</span>
                </div>
            </div>
        </div>

        <div class="buttons">
            <button id="playBtn" class="btn btn-primary">▶️ 播放</button>
            <button id="pauseBtn" class="btn btn-secondary" disabled>⏸️ 暂停</button>
            <button id="resumeBtn" class="btn btn-secondary" disabled>▶️ 继续</button>
            <button id="stopBtn" class="btn btn-danger" disabled>⏹️ 停止</button>
            <button id="downloadBtn" class="btn btn-download">💾 下载语音</button>
        </div>

        <div id="status" class="status" style="display: none;">
            <div id="statusText"></div>
            <div class="progress-bar">
                <div id="progressFill" class="progress-fill"></div>
            </div>
        </div>

        <div class="feature-list">
            <div class="feature-item">
                <div class="feature-icon">🎯</div>
                <div class="feature-title">精确控制</div>
                <div class="feature-desc">支持语速、音调、音量的精细调节</div>
            </div>
            <div class="feature-item">
                <div class="feature-icon">🌍</div>
                <div class="feature-title">多语言支持</div>
                <div class="feature-desc">支持多种语言和方言的语音合成</div>
            </div>
            <div class="feature-item">
                <div class="feature-icon">💾</div>
                <div class="feature-title">离线下载</div>
                <div class="feature-desc">生成的语音可直接下载保存</div>
            </div>
            <div class="feature-item">
                <div class="feature-icon">⚡</div>
                <div class="feature-title">实时处理</div>
                <div class="feature-desc">无需等待，即时生成高质量语音</div>
            </div>
        </div>
    </div>

    <script>
        class TTSManager {
            constructor() {
                this.synth = window.speechSynthesis;
                this.utterance = null;
                this.isPlaying = false;
                this.isPaused = false;
                this.audioData = null;
                this.mediaRecorder = null;
                this.recordedChunks = [];
                
                this.initializeElements();
                this.loadVoices();
                this.bindEvents();
            }

            initializeElements() {
                this.elements = {
                    textInput: document.getElementById('textInput'),
                    voiceSelect: document.getElementById('voiceSelect'),
                    rateRange: document.getElementById('rateRange'),
                    rateValue: document.getElementById('rateValue'),
                    pitchRange: document.getElementById('pitchRange'),
                    pitchValue: document.getElementById('pitchValue'),
                    volumeRange: document.getElementById('volumeRange'),
                    volumeValue: document.getElementById('volumeValue'),
                    playBtn: document.getElementById('playBtn'),
                    pauseBtn: document.getElementById('pauseBtn'),
                    resumeBtn: document.getElementById('resumeBtn'),
                    stopBtn: document.getElementById('stopBtn'),
                    downloadBtn: document.getElementById('downloadBtn'),
                    status: document.getElementById('status'),
                    statusText: document.getElementById('statusText'),
                    progressFill: document.getElementById('progressFill')
                };
            }

            loadVoices() {
                const loadVoicesAsync = () => {
                    const voices = this.synth.getVoices();
                    this.elements.voiceSelect.innerHTML = '';
                    
                    if (voices.length === 0) {
                        this.elements.voiceSelect.innerHTML = '<option value="">没有可用的语音</option>';
                        return;
                    }

                    // 优先显示中文语音
                    const chineseVoices = voices.filter(voice => 
                        voice.lang.startsWith('zh') || 
                        voice.name.includes('Chinese') ||
                        voice.name.includes('Mandarin')
                    );
                    
                    const otherVoices = voices.filter(voice => 
                        !voice.lang.startsWith('zh') && 
                        !voice.name.includes('Chinese') &&
                        !voice.name.includes('Mandarin')
                    );

                    // 添加中文语音
                    if (chineseVoices.length > 0) {
                        const chineseGroup = document.createElement('optgroup');
                        chineseGroup.label = '中文语音';
                        chineseVoices.forEach((voice, index) => {
                            const option = document.createElement('option');
                            option.value = index;
                            option.textContent = `${voice.name} (${voice.lang})`;
                            if (voice.default) option.selected = true;
                            chineseGroup.appendChild(option);
                        });
                        this.elements.voiceSelect.appendChild(chineseGroup);
                    }

                    // 添加其他语音
                    if (otherVoices.length > 0) {
                        const otherGroup = document.createElement('optgroup');
                        otherGroup.label = '其他语音';
                        otherVoices.forEach((voice, index) => {
                            const option = document.createElement('option');
                            option.value = chineseVoices.length + index;
                            option.textContent = `${voice.name} (${voice.lang})`;
                            otherGroup.appendChild(option);
                        });
                        this.elements.voiceSelect.appendChild(otherGroup);
                    }

                    // 如果没有选中的语音，选择第一个中文语音或第一个语音
                    if (!this.elements.voiceSelect.value && voices.length > 0) {
                        this.elements.voiceSelect.value = 0;
                    }
                };

                // 加载语音列表
                if (this.synth.getVoices().length > 0) {
                    loadVoicesAsync();
                } else {
                    this.synth.addEventListener('voiceschanged', loadVoicesAsync);
                }
            }

            bindEvents() {
                // 范围滑块事件
                this.elements.rateRange.addEventListener('input', (e) => {
                    this.elements.rateValue.textContent = parseFloat(e.target.value).toFixed(1);
                });

                this.elements.pitchRange.addEventListener('input', (e) => {
                    this.elements.pitchValue.textContent = parseFloat(e.target.value).toFixed(1);
                });

                this.elements.volumeRange.addEventListener('input', (e) => {
                    this.elements.volumeValue.textContent = parseFloat(e.target.value).toFixed(1);
                });

                // 按钮事件
                this.elements.playBtn.addEventListener('click', () => this.play());
                this.elements.pauseBtn.addEventListener('click', () => this.pause());
                this.elements.resumeBtn.addEventListener('click', () => this.resume());
                this.elements.stopBtn.addEventListener('click', () => this.stop());
                this.elements.downloadBtn.addEventListener('click', () => this.downloadAudio());

                // 键盘快捷键
                document.addEventListener('keydown', (e) => {
                    if (e.ctrlKey || e.metaKey) {
                        switch(e.key) {
                            case 'Enter':
                                e.preventDefault();
                                this.play();
                                break;
                            case ' ':
                                e.preventDefault();
                                if (this.isPlaying && !this.isPaused) {
                                    this.pause();
                                } else if (this.isPaused) {
                                    this.resume();
                                }
                                break;
                        }
                    }
                });
            }

            createUtterance(text) {
                const utterance = new SpeechSynthesisUtterance(text);
                const voices = this.synth.getVoices();
                const selectedVoiceIndex = this.elements.voiceSelect.value;
                
                if (selectedVoiceIndex && voices[selectedVoiceIndex]) {
                    utterance.voice = voices[selectedVoiceIndex];
                }
                
                utterance.rate = parseFloat(this.elements.rateRange.value);
                utterance.pitch = parseFloat(this.elements.pitchRange.value);
                utterance.volume = parseFloat(this.elements.volumeRange.value);

                return utterance;
            }

            play() {
                const text = this.elements.textInput.value.trim();
                if (!text) {
                    alert('请输入要转换的文本！');
                    return;
                }

                this.stop(); // 先停止之前的播放
                
                this.utterance = this.createUtterance(text);
                
                // 事件监听
                this.utterance.onstart = () => {
                    this.isPlaying = true;
                    this.isPaused = false;
                    this.updateUI();
                    this.showStatus('正在播放语音...', 'speaking');
                    this.startProgress();
                };

                this.utterance.onend = () => {
                    this.isPlaying = false;
                    this.isPaused = false;
                    this.updateUI();
                    this.showStatus('播放完成', 'stopped');
                    this.resetProgress();
                };

                this.utterance.onerror = (event) => {
                    console.error('语音合成错误:', event.error);
                    this.isPlaying = false;
                    this.isPaused = false;
                    this.updateUI();
                    this.showStatus('播放出错: ' + event.error, 'stopped');
                };

                this.utterance.onpause = () => {
                    this.isPaused = true;
                    this.updateUI();
                    this.showStatus('播放已暂停', 'paused');
                };

                this.utterance.onresume = () => {
                    this.isPaused = false;
                    this.updateUI();
                    this.showStatus('继续播放中...', 'speaking');
                };

                this.synth.speak(this.utterance);
            }

            pause() {
                if (this.isPlaying && !this.isPaused) {
                    this.synth.pause();
                }
            }

            resume() {
                if (this.isPlaying && this.isPaused) {
                    this.synth.resume();
                }
            }

            stop() {
                this.synth.cancel();
                this.isPlaying = false;
                this.isPaused = false;
                this.updateUI();
                this.hideStatus();
                this.resetProgress();
            }

            async downloadAudio() {
                const text = this.elements.textInput.value.trim();
                if (!text) {
                    alert('请输入要转换的文本！');
                    return;
                }

                try {
                    // 创建一个临时的utterance用于录制
                    const utterance = this.createUtterance(text);
                    
                    // 使用Web Audio API录制音频
                    const audioContext = new (window.AudioContext || window.webkitAudioContext)();
                    const destination = audioContext.createMediaStreamDestination();
                    
                    // 创建语音合成并连接到目标
                    this.showStatus('正在生成音频文件...', 'speaking');
                    
                    // 使用SpeechSynthesisUtterance播放并录制
                    const recordedChunks = [];
                    const mediaRecorder = new MediaRecorder(destination.stream);
                    
                    mediaRecorder.ondataavailable = (event) => {
                        if (event.data.size > 0) {
                            recordedChunks.push(event.data);
                        }
                    };

                    mediaRecorder.onstop = () => {
                        const blob = new Blob(recordedChunks, { type: 'audio/wav' });
                        const url = URL.createObjectURL(blob);
                        const link = document.createElement('a');
                        link.href = url;
                        link.download = `tts_audio_${new Date().getTime()}.wav`;
                        document.body.appendChild(link);
                        link.click();
                        document.body.removeChild(link);
                        URL.revokeObjectURL(url);
                        this.showStatus('音频文件下载完成！', 'stopped');
                        setTimeout(() => this.hideStatus(), 3000);
                    };

                    utterance.onstart = () => {
                        mediaRecorder.start();
                    };

                    utterance.onend = () => {
                        setTimeout(() => {
                            mediaRecorder.stop();
                        }, 100);
                    };

                    utterance.onerror = () => {
                        this.showStatus('生成音频文件失败', 'stopped');
                        setTimeout(() => this.hideStatus(), 3000);
                    };

                    this.synth.speak(utterance);

                } catch (error) {
                    console.error('下载音频失败:', error);
                    this.showStatus('下载失败，请尝试其他方法', 'stopped');
                    setTimeout(() => this.hideStatus(), 3000);
                }
            }

            updateUI() {
                this.elements.playBtn.disabled = this.isPlaying;
                this.elements.pauseBtn.disabled = !this.isPlaying || this.isPaused;
                this.elements.resumeBtn.disabled = !this.isPaused;
                this.elements.stopBtn.disabled = !this.isPlaying;
            }

            showStatus(message, type) {
                this.elements.statusText.textContent = message;
                this.elements.status.className = `status ${type}`;
                this.elements.status.style.display = 'block';
            }

            hideStatus() {
                this.elements.status.style.display = 'none';
            }

            startProgress() {
                let progress = 0;
                const interval = setInterval(() => {
                    if (!this.isPlaying || this.isPaused) {
                        clearInterval(interval);
                        return;
                    }
                    progress += 2;
                    if (progress >= 100) {
                        progress = 100;
                        clearInterval(interval);
                    }
                    this.elements.progressFill.style.width = progress + '%';
                }, 100);
            }

            resetProgress() {
                this.elements.progressFill.style.width = '0%';
            }
        }

        // 检查浏览器支持
        if ('speechSynthesis' in window) {
            // 初始化TTS管理器
            const ttsManager = new TTSManager();
            
            // 添加使用提示
            console.log('🎙️ TTS工具已加载完成！');
            console.log('💡 快捷键：Ctrl+Enter 播放，Ctrl+Space 暂停/继续');
        } else {
            alert('很抱歉，您的浏览器不支持语音合成功能。请使用Chrome、Firefox、Safari或Edge等现代浏览器。');
        }
    </script>
</body>
</html>